// while in binary out mode, the format will be
// s_id ambiguous_id word_id .... s_id
// s_id is get by parameter -s, ambiguous_id by -a
// for instance, the output for" 为人民办实事的精神" is
// comman: mmseg -d dict.utf8 -f bin -s 10 -a 9 zh.utf8
//  0a00 0000 0900 0000 4b08 0100 cc21 0100  ........K....!..
//  0a00 0000
//  
//  0a00 0000 -> s_id
//  0900 0000 -> ambiguous_id
//  4b08 0100 -> 的
//  cc21 0100 -> 精神

#include <getopt.h>
#include <stdio.h>
#include <locale.h>

#include "dict.h"
#include "sen.h"

static char *s_strDictFile = NULL;
static bool s_bTextOut = false;
static bool s_bShowId = false;
static TWORDID s_iSTOKID = 10;
static TWORDID s_iAmbiID = 0;

static CDict *s_dict = NULL;

static struct option long_options[] =
{
  {"dict", 1, 0, 'd'},
  {"format", 1, 0, 'f'},
  {"show-id", 0, 0, 'i'},
  {"s-tok", 1, 0, 's'},
  {"ambiguous-id", 1, 0, 'a'},
  {0, 0, 0, 0}
};

static void
getParameters(int argc, char *argv[])
{
  int c;
  while ((c=getopt_long(argc, argv, "d:if:s:a:", long_options, NULL)) != -1) {
    switch (c) {
    case 'd':
      s_strDictFile = strdup(optarg);
      break;
    case 'i':
      s_bShowId = true;
      break;
    case 'f':
      s_bTextOut = (strcmp(optarg, "text") == 0);
      break;
    case 's':
      s_iSTOKID = atoi(optarg);
      break;
    case 'a':
      s_iAmbiID = atoi(optarg);
      break;
    default:
      printf("WOw!\n");
      break;
    }
  }
  if (s_strDictFile == NULL)
    printf("Wow!\n");
}

static void
output_stok(int &nWords)
{
  if (s_bShowId) {
    if (nWords > 0)
      printf(" ");
  } else {
    fwrite(&s_iSTOKID, sizeof(TWORDID), 1, stdout);
  }
  ++nWords;
}

static void
output(int len, const TWCHAR *p, TWORDID idprev, TWORDID idcur, int &nWords)
{
  static char mbword[1024];
  static TWCHAR wcword[1024];

  bool bRealGap = (idcur != ID_NOT_WORD || idprev != ID_NOT_WORD);
  if (s_bTextOut) {
    for (int i = 0; i < len; ++i, ++p)
      wcword[i] = *p;
    wcword[len] = 0;
    WCSTOMBS(mbword, wcword, sizeof(mbword));
    if (bRealGap && idprev == ID_NOT_WORD)
      printf("(%d)", unsigned(idprev));
    if (bRealGap && (nWords >0))
      printf(" ");

    (s_iAmbiID && idcur == s_iAmbiID)?printf("<ambi>%s</ambi>", mbword):
      printf("%s", mbword);
    if (s_bShowId && idcur != ID_NOT_WORD)
      printf("(%d)", unsigned(idcur));
  } else {
    if (bRealGap) {
      if (s_bShowId) {
        if (nWords > 0)
          printf(" ");
        printf("%d", unsigned(idcur));
      } else
        fwrite(&idcur, sizeof(TWORDID), 1, stdout);
    }
  }
    if (bRealGap)
      ++nWords;
}

int
getAmbiLen(const TWCHAR *p, int word_len)
{
  const CDict::TState *pstate;

  for (int i = 1; i < word_len && *(p+i) != WCH_NULL; ++i) {
    int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p+i);
    if (word_len < i + len)
      word_len = i + len;
  }
  return word_len;
}


static bool
processSingleFile(FILE *fp, int &nWords, int &nAmbis)
{
  nWords = 0;
  nAmbis = 0;

  wstring sntnc;
  CCharReader *pReader = new CCharReader(fp);
  CCharReader::iterator iter = pReader->begin();
  TWORDID idcur, idprev = s_iSTOKID;

  if (!s_bTextOut)              // binary Output
    output_stok(nWords);

  while (true) {
    if (ReadSentence(sntnc, iter, false) == false)
      break;

    for (const TWCHAR *p = sntnc.c_str(); (*p);) {
      const CDict::TState *pstate;
      int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p);
      if (len <= 0) {
        idcur = ID_NOT_WORD;
        len = 1;
      } else
        idcur = pstate->word_id;
      if (s_iAmbiID != WCH_NULL) {
        int ambiLen = getAmbiLen(p, len);
        if (ambiLen > len) {
          len = ambiLen;
          idcur = s_iAmbiID;
          ++nAmbis;
        }
      }
      output(len, p, idprev, idcur, nWords);

      idprev = idcur;
      p += len;
    }
    if (!s_bTextOut) {
      output_stok(nWords);
      idprev = s_iSTOKID;
    }
  }
  fflush(stdout);
  return true;
}

#ifdef TESTMMSG

int
main(int argc, char *argv[])
{
  int nWords, nAmbis;

  setlocale(LC_ALL, "");
  getParameters(argc, argv);
  argc -= optind;
  argv += optind;

  fprintf(stderr, "Loading lexicon....");fflush(stderr);

  s_dict = new CDict();
  if (!s_dict->parseText(s_strDictFile)) {
    fprintf(stderr, "fail\n"); fflush(stderr);
    exit(1001);
  }
  fprintf(stderr, "done"); fflush(stderr);

  if (argc == 0) {
    fprintf(stderr, "\nProcessing from stdin..."); fflush(stderr);
    processSingleFile(stdin, nWords, nAmbis);
  } else {
    for (int i = 0; i < argc; ++i) {
      fprintf(stderr, "\nProcessing %s...", argv[i]); fflush(stderr);
      FILE *fp = fopen(argv[i], "r");
      if (fp != NULL) {
        processSingleFile(fp, nWords, nAmbis);
        fprintf(stderr, "@Offset %u, %d words, %d ambiguious, Done\n",
                ftell(fp), nWords, nAmbis); fflush(stderr);
      } else {
        fprintf(stderr, "Can not Open!!!!!\n"); fflush(stderr);
      }
      fclose(fp);
    }
  }

  delete s_dict;
  return 0;
}

#endif
